/*
 * Copyright (c) Tan Menglong <TanMenglong@gmail.com>
 * All rights reserved.
 * 
 * This file is part of the RabbitOS.  The RabbitOS is free software, also known
 * as "open source;" you can redistribute it and/or modify it under the terms
 * of the GNU General Public License (GPL), version 2, as published by the Free
 * Software Foundation (FSF).  To explore alternate licensing terms, contact
 * the Rabbit OS team.
 * 
 * The RabbitOS is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GPL for more details.  You should have
 * received a copy of the GPL along with the RabbitOS; see the file COPYING. If
 * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
 *
 */
/* Functions to operate console.
 * 02-May-08
 */

#include <rabbit/console.h>

cursor_t cursor;
u16int *video_memory = (u16int *) 0xB8000;

/*
 * Initialize variables of console.
 */
void console_init(void)
{
	cursor.x = 0;
	cursor.y = 0;
}

/*
 * Print a char on the screen in a simple way.
 */
void console_putc(const char c)
{
	console_putchar(c, 15 /*white */ , 0 /*black */ );
}

/*
 * Print a string on the screen in a simple way.
 */
void console_puts(const char *c)
{
	int i = 0;
	while (c[i]) {
		console_putc(c[i++]);
	}
}

/*
 * Print a char on the screen.
 */
void console_putchar(const char c, char fcolor, char bcolor)
{
	u16int attrib = (bcolor << 4) | (fcolor & 0x0F);

	switch (c) {
	case '\n':
		console_cursor_newline();
		break;
	default:
		video_memory[cursor.y * 80 + cursor.x] = c | (attrib << 8);
		console_next_cursor();
	}

}

/*
 * Print a string on the screen.
 */
void console_putstring(const char *c, char fcolor, char bcolor)
{
	int i = 0;
	while (c[i]) {
		console_putchar(c[i++], fcolor, bcolor);
	}
}

/*
 *
 */
void console_cursor_newline(void)
{
	cursor.x = 0;
	cursor.y++;
	if (cursor.y == 25) {
		console_scroll();
	}
	console_move_cursor();
}

void console_next_cursor(void)
{
	cursor.x++;
	if (cursor.x == 80)
		console_cursor_newline();
	else
		console_move_cursor();
}

void console_clear(void)
{
	char attrib = (0 /*black */  << 4) | (15 /*white */  & 0x0F);
	u16int blank = 0x20 /* space */  | (attrib << 8);
	int i;
	for (i = 0; i < 25 * 80; i++) {
		video_memory[i] = blank;
	}
	cursor.x == 0;
	cursor.y == 0;
	console_move_cursor();
}

void console_scroll(void)
{
	if (cursor.y == 0) {
		console_clear();
		return;
	}

	char attrib = (0 /*black */  << 4) | (15 /*white */  & 0x0F);
	u16int blank = 0x20 /* space */  | (attrib << 8);

	int i;
	for (i = 0 * 80; i < 24 * 80; i++) {
		video_memory[i] = video_memory[i + 80];
	}

	for (i = 24 * 80; i < 25 * 80; i++) {
		video_memory[i] = blank;
	}
	//if(cursor.y==25)
	cursor.y--;
	console_move_cursor();

}

void console_set_cursor(int x, int y)
{
	if (x > 80 || y > 25)
		/*Move cursor out of range. */
		return;
	cursor.x = x;
	cursor.y = y;
	console_move_cursor();
}

void console_move_cursor(void)
{
	u16int cursor_location = cursor.y * 80 + cursor.x;
	//Tell the VGA board we are setting the high cursor byte.
	outb(0x3D4, 14);
	// Send the high cursor byte.
	outb(0x3D5, cursor_location >> 8);
	// Tell the VGA board we are setting the low cursor byte.
	outb(0x3D4, 15);
	// Send the low cursor byte.
	outb(0x3D5, cursor_location);
}
